package com.base.config;

import com.base.exception.BaseException;
import com.base.exception.JailException;
import com.base.exception.ModelAndViewRuntimeException;
import com.base.pay.exception.AliRuntimeException;
import com.base.pay.exception.WxRuntimeException;
import com.base.result.ResponseResult;
import com.base.result.ResponseResultUtils;
import com.base.result.ResultEnum;
import com.base.exception.CustomException;
import com.base.self.common.SelfRuntimeException;
import com.base.self.common.SelfRuntimeOkException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 对Controller层异常的统一处理
 */
@Slf4j
@Component
@ControllerAdvice
public class CallAPIExceptionHandler {

    private void printWriterInfo(Throwable t){
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            t.printStackTrace(pw);
        }
        log.error(sw.toString());
    }


    @ExceptionHandler(ModelAndViewRuntimeException.class)
    public String exceptionHandler(ModelAndViewRuntimeException t) {
        return t.getModelAndView();
    }

    @ExceptionHandler(JailException.class)
    @ResponseBody
    public Map<String, Object> exceptionHandler(JailException t) {
        return t.getMap();
    }


    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult exceptionHandler(CustomException t) {
        return ResponseResultUtils.getResponseResultF(t.getMessage());
    }



    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public ResponseResult exceptionHandler(Throwable t) {
        printWriterInfo(t);
        return ResponseResultUtils.getResponseResult(ResultEnum.FAILED.getCode(), "系统异常");
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult exceptionHandler(Exception e) {
        printWriterInfo(e);
        return ResponseResultUtils.getResponseResult(ResultEnum.FAILED.getCode(), "系统异常");
    }

    @ExceptionHandler(SelfRuntimeOkException.class)
    @ResponseBody
    public ResponseResult SelfRuntimeOkExceptionHandler(SelfRuntimeOkException selfRuntimeOkException) {
        return selfRuntimeOkException.getResponseResult();
    }
    /**
     * 运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public ResponseResult runtimeExceptionHandler(RuntimeException runtimeException) {
        printWriterInfo(runtimeException);
        if (runtimeException instanceof SelfRuntimeException) {
            return ((SelfRuntimeException) runtimeException).getResponseResult();
        }
        if (runtimeException instanceof AliRuntimeException) {
            return ResponseResultUtils.getResponseResult(ResultEnum.FAILED.getCode(), runtimeException.getMessage());
        }
        if (runtimeException instanceof WxRuntimeException) {
            return ResponseResultUtils.getResponseResult(ResultEnum.FAILED.getCode(), runtimeException.getMessage());
        }
        return ResponseResultUtils.getResponseResult(ResultEnum.FAILED.getCode(), "系统开了一会小差");
    }
    /**
     * 运行时异常
     */
    @ExceptionHandler(BaseException.class)
    @ResponseBody
    public ResponseResult baseExceptionExceptionHandler(BaseException baseException) {
        printWriterInfo(baseException);
        return baseException.getResponseResult();
    }

    /**
     * 处理BindException异常 参数异常提示
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public ResponseResult errorHandlerThrowable(BindException bindException) {
        printWriterInfo(bindException);
        BindingResult bindingResult = bindException.getBindingResult();
        FieldError fieldError = bindingResult.getFieldError();
        AtomicReference<String> message = new AtomicReference<>("");
        Optional.ofNullable(fieldError).ifPresent(x -> message.set(x.getDefaultMessage()));
        return ResponseResultUtils.getResponseResult(ResultEnum.SYSTEM_PARAM_ERR.getCode(), message.get());
    }

}
